package com.alibaba.datax.plugin.rdbms.util;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

/**
 * @author: liangdf
 * @date: 2019/3/13 15:00
 * @description: RSA工具类
 */
public class RSAUtil {
    private static final String ENCODING = "UTF-8";
    /**
     * 定义加密方式
     */
    private final static String KEY_RSA = "RSA";
    /**
     * 定义签名算法
     */
    private final static String KEY_RSA_SIGNATURE = "MD5withRSA";
    /**
     * 定义公钥算法
     */
    private final static String KEY_RSA_PUBLICKEY = "RSAPublicKey";
    /**
     * 定义私钥算法
     */
    private final static String KEY_RSA_PRIVATEKEY = "RSAPrivateKey";

    public final static  String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjopmGQevlkG9agI2XuPZ9nInvLHcJTcpNWiTQRyG14V/Ft+1VmzfLft92GxiNsHEDrykXref9I+SCbNYL8mIgppYUujTRPUeyALLlAPv4OOSjwKRnX04/W3tJczl/rJMsOdprAIencWNNGALy1IeYzJRSg39OCLKkoCWRwJWzUDG61z5DhUhK/Pj7cZocXYj4zN+HaBVnakVcn+I+cz1zKZ323XyzJEDWpEBnWwVNYukCf3CcNaOmvfBQOtwygbhtOOyHclkI7J13B6iyvKnl1j3i3RlnOtpgi69+o6TuC7vTZOctURGqU/rG3pDA4XXpemLnVvBWoordMQH7df50QIDAQAB";
    public final static  String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCOimYZB6+WQb1qAjZe49n2cie8sdwlNyk1aJNBHIbXhX8W37VWbN8t+33YbGI2wcQOvKRet5/0j5IJs1gvyYiCmlhS6NNE9R7IAsuUA+/g45KPApGdfTj9be0lzOX+skyw52msAh6dxY00YAvLUh5jMlFKDf04IsqSgJZHAlbNQMbrXPkOFSEr8+PtxmhxdiPjM34doFWdqRVyf4j5zPXMpnfbdfLMkQNakQGdbBU1i6QJ/cJw1o6a98FA63DKBuG047IdyWQjsnXcHqLK8qeXWPeLdGWc62mCLr36jpO4Lu9Nk5y1REapT+sbekMDhdel6YudW8Faiit0xAft1/nRAgMBAAECggEBAI1sNVY6MPU0rnjCTy2ghb4ljtWB5jkqXIF4Czn70rF86xZHyMRB6sDVmAulpWBMqXgxpCexqktcMvna7fEj1IQ4HM/N3ue5B9xMIa3upg6L2/p2AwGtn2Cas0Lg44TrZHnUcBzQUY4Z1jqT3L/S7wFeiBaggI80vaXTXMaBRJwJYL4ahesvRZpS5elg8Bu1ZzLzVmtlrOyQNCIRo1KfSKSLT1zc0aq34WLRWbXSYQRelQ3TNz4J47R9rOEOueB7YDTJbMDKpSmAld06+y8CNykRFo3is7CD3eqyER458jnCV5GDCCISklRl1BwIv+ICZikq3cNGeBWlSKSgT7CPeZECgYEAxm7z5aF4IT8Ts4Pm8Jv0FCOZ0k6iTJRWE9MNPTBo2HE7gan0QxpMyALzQmhi84AeUozvmIqFsmktBwR5JunCzupyPaLSdcr9YJNUDO7NY03oTqL66F2YpOAYqvcM6rl896yyyrKSTMf9P3iF/U4kcUOUc1ImJYbupTZhu6AgQuUCgYEAt+R1T+wjW2CKeGfclpN3NRcTbW1AEw0njdouOPty0Y6xwyoTnZh09uTA1f6Gz7hho6lQle+OPnVSrEnDXms5R3jZURHJxOR9cm2gjjjZo5EW/Zk2Zjr7g1m0CsCoo6dJPW/qGfbHZGTL+TWKKCVhjoc19/1VUgOUSXOnFta1EH0CgYEAnI2C3QNEXK6AI5wIAoJ30b+4pwSk5VgOhTt4cXMU9NZ5BTaJ4LsKIq65LwZeMxA8XBKXITkAfB6giK3Ny5aXvFmZYelos8g/mQcDQ+TPo+4ePpQ08kiNml6294NL7JAE+P6GXIcAB5WsxnuW8p7I/5c6srT4JZlMBIpgFwAhE8UCgYBu2eblwMEnijCumF1e35ISjNCHPD5NvbZESmtmqhzyugPqU+jzLT4EvqyH0yDNAqbJE32ihH/IosytUuHUfupObUkDF6f7aok8e103nomDkii7wqoKQi/vZBmmCbEexe7efCIweJSFrkVO+rlHrhD67ALadPoDsGipRnBI0jDfuQKBgHaSekUDhKsK1Nt03gQZ12vM8pQYf/ZXXW74QqI0z//8rJdkOC7xipMes/6mm0fKsR4CtvosLrjZGStesFPSOk96rqkzOECIHZR6IRy3zC17mRKHeZLDacLbj4oRGWuX8Kag3j408sluQrhi7MSsY2fMJR+ub/EVAlkOOQJPiYJP";
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 初始化密钥
     */
    public static Map<String, Object> init() {
        Map<String, Object> map = null;
        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA);
            generator.initialize(2048);
            KeyPair keyPair = generator.generateKeyPair();
            // 公钥
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            // 私钥
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            // 将密钥封装为map
            map = new HashMap(16);
            map.put(KEY_RSA_PUBLICKEY, publicKey);
            map.put(KEY_RSA_PRIVATEKEY, privateKey);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 公钥加密
     *
     * @param data 待加密数据
     * @param key  公钥
     */
    public static byte[] encryptByPublicKey(String data, String key) {
        byte[] result = null;
        try {
            byte[] bytes = decryptBase64(key);
            // 取得公钥
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            PublicKey publicKey = factory.generatePublic(keySpec);
            // 对数据加密
            Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", "BC");

            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] encode = cipher.doFinal(data.getBytes());
            // 再进行Base64加密
            result = Base64.encode(encode);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 私钥解密
     *
     * @param data 加密数据
     * @param key  私钥
     */
    public static String decryptByPrivateKey(byte[] data, String key) {
        String result = null;
        try {
            // 对私钥解密
            byte[] bytes = decryptBase64(key);
            // 取得私钥
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            PrivateKey privateKey = factory.generatePrivate(keySpec);
            // 对数据解密
            Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", "BC");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            // 先Base64解密
            byte[] decoded = Base64.decode(data);
            result = new String(cipher.doFinal(decoded));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 获取公钥
     */
    public static String getPublicKey(Map<String, Object> map) {
        String str = "";
        try {
            Key key = (Key) map.get(KEY_RSA_PUBLICKEY);
            str = encryptBase64(key.getEncoded());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 获取私钥
     */
    public static String getPrivateKey(Map<String, Object> map) {
        String str = "";
        try {
            Key key = (Key) map.get(KEY_RSA_PRIVATEKEY);
            str = encryptBase64(key.getEncoded());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 用私钥对信息生成数字签名
     *
     * @param data       加密数据
     * @param privateKey 私钥
     */
    public static String sign(byte[] data, String privateKey) {
        String str = "";
        try {
            // 解密由base64编码的私钥
            byte[] bytes = decryptBase64(privateKey);
            // 构造PKCS8EncodedKeySpec对象
            PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes);
            // 指定的加密算法
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            // 取私钥对象
            PrivateKey key = factory.generatePrivate(pkcs);
            // 用私钥对信息生成数字签名
            Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
            signature.initSign(key);
            signature.update(data);
            str = encryptBase64(signature.sign());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 校验数字签名
     *
     * @param data      加密数据
     * @param publicKey 公钥
     * @param sign      数字签名
     * @return 校验成功返回true，失败返回false
     */
    public static boolean verify(byte[] data, String publicKey, String sign) {
        boolean flag = false;
        try {
            // 解密由base64编码的公钥
            byte[] bytes = decryptBase64(publicKey);
            // 构造X509EncodedKeySpec对象
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
            // 指定的加密算法
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            // 取公钥对象
            PublicKey key = factory.generatePublic(keySpec);
            // 用公钥验证数字签名
            Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
            signature.initVerify(key);
            signature.update(data);
            flag = signature.verify(decryptBase64(sign));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }


    /**
     * BASE64 解密
     *
     * @param key 需要解密的字符串
     * @return 字节数组
     */
    public static byte[] decryptBase64(String key) throws Exception {
        return Base64.decode(key);
    }

    /**
     * BASE64 加密
     *
     * @param key 需要加密的字节数组
     * @return 字符串
     */
    public static String encryptBase64(byte[] key) throws Exception {
        return new String(Base64.encode(key));
    }


    public static void main(String[] args) throws Exception {
//        String publicKey = "";
//        String privateKey = "";
//        Map<String, Object> keyMap = RSAUtil.init();
//        publicKey = RSAUtil.getPublicKey(keyMap);
//        privateKey = RSAUtil.getPrivateKey(keyMap);
        System.out.println("公钥：\n\r" + publicKey);
        System.out.println("私钥：\n\r" + privateKey);

        System.out.println("公钥加密======私钥解密");
        String str = "dbc";
        byte[] enStr = RSAUtil.encryptByPublicKey(str, publicKey);
        String ENSTR=new String(enStr,ENCODING);
        System.out.println("加密前：" + str + "\n\r加密后：" + ENSTR);

         String decStr = RSAUtil.decryptByPrivateKey(ENSTR.getBytes(), privateKey);
        System.out.println("加密前：" + str + "\n\r解密后：" + decStr);

        System.out.println("\n\r");
        System.out.println("私钥签名======公钥验证");
        String sign = RSAUtil.sign(str.getBytes(), privateKey);
        System.out.println("签名：\n\r" + sign);
        boolean flag = RSAUtil.verify(str.getBytes(), publicKey, sign);
        System.out.println("验签结果：\n\r" + flag);
    }
}
